package com.derbysoft.lowcostadapter.dswitch3.service.impl;

import com.derbysoft.dswitch.dto.hotel.avail.AvailRoomStayDTO;
import com.derbysoft.dswitch.dto.hotel.common.StayDateRangeDTO;
import com.derbysoft.dswitch.remote.hotel.dto.HotelAvailRequest;
import com.derbysoft.dswitch.remote.hotel.dto.HotelAvailResponse;
import com.derbysoft.lowcostadapter.commons.model.Hotel;
import com.derbysoft.lowcostadapter.commons.model.RoomStay;
import com.derbysoft.lowcostadapter.commons.redis.service.RoomStayCacheService;
import com.derbysoft.lowcostadapter.commons.redis.utils.KeyValueHelper;
import com.derbysoft.lowcostadapter.commons.utils.DateTimeUtils;
import com.derbysoft.lowcostadapter.dswitch2.service.RoomStayService;
import com.derbysoft.lowcostadapter.schedule.parse.ParseRoomStayService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by: jason
 * Date: 2012-09-13
 */
@Service("ds3RoomStayService")
public class DS3RoomStayServiceImpl implements RoomStayService<HotelAvailRequest, HotelAvailResponse> {

    private static final int DELAY_ONE_DAY = -24;
    private static Logger logger = LoggerFactory.getLogger(DS3RoomStayServiceImpl.class);

    @Autowired
    private RoomStayCacheService roomStayCacheService;

    @Autowired
    private ParseRoomStayService parseRoomStayService;

    @Override
    public HotelAvailResponse filter(HotelAvailRequest request, HotelAvailResponse hotelAvailResponse, Hotel hotel) {
        if (parseRoomStayService.isParsing()) {
            logger.info("parseRoomStayService is running ...");
            return null;
        }

        List<AvailRoomStayDTO> availRoomStayDTOs = new ArrayList<AvailRoomStayDTO>();
        StayDateRangeDTO stayDateRangeDTO = request.getHotelAvailRQ().getAvailCriteria().getStayDateRange();
        int los = DateTimeUtils.getIntervalDays(stayDateRangeDTO.getCheckin(), stayDateRangeDTO.getCheckout());
        for (AvailRoomStayDTO roomStayDTO : hotelAvailResponse.getHotelAvailRS().getHotelAvailRoomStaysList().get(0).getRoomStaysList()) {
            String roomTypeId = roomStayDTO.getRoomType().getCode();
            if (!roomStayRestricted(stayDateRangeDTO, hotel.getPropertyID(), roomTypeId, los)) {
                availRoomStayDTOs.add(roomStayDTO);
            }
        }
        if (availRoomStayDTOs.isEmpty()) {
            return null;
        }
        hotelAvailResponse.getHotelAvailRS().getHotelAvailRoomStaysList().get(0).getRoomStaysList().clear();
        hotelAvailResponse.getHotelAvailRS().getHotelAvailRoomStaysList().get(0).setRoomStaysList(availRoomStayDTOs);
        return hotelAvailResponse;
    }

    private boolean roomStayRestricted(StayDateRangeDTO stayDateRange, int propertyID, String roomTypeId, int los) {
        Date checkInDate = DateTimeUtils.parse(stayDateRange.getCheckin());
        Date checkOutDate = DateTimeUtils.parse(stayDateRange.getCheckout());
        String hotelLevel = RoomStay.PREFIX + KeyValueHelper.SEPARATOR + propertyID + KeyValueHelper.SEPARATOR + 0;
        List<RoomStay> roomStays = roomStayCacheService.loadAll(hotelLevel);
        if (CollectionUtils.isEmpty(roomStays)) {
            return !CollectionUtils.isEmpty(roomStays)
                    && checkRoomStays(propertyID, roomTypeId, los, checkInDate, checkOutDate);
        }
        if (!inStayDateRange(roomStays, checkInDate, checkOutDate)) {
            return checkRoomStays(propertyID, roomTypeId, los, checkInDate, checkOutDate);
        }

        for (RoomStay roomStay : roomStays) {
            if (!losIsAvailable(los, roomStay)) {
                return true;
            }
        }
        return false;
    }

    private boolean inStayDateRange(List<RoomStay> roomStays, Date checkInDate, Date checkOutDate) {
        for (RoomStay roomStay : roomStays) {
            Date start = DateTimeUtils.parse(roomStay.getStart());
            Date end = DateTimeUtils.parse(roomStay.getEnd());
            if (checkInDate.compareTo(start) >= 0 && DateTimeUtils.addHours(checkOutDate, DELAY_ONE_DAY).compareTo(end) <= 0) {
                return true;
            }
        }
        return false;
    }

    private boolean checkRoomStays(int propertyID, String roomTypeId, int los, Date checkInDate, Date checkOutDate) {
        String roomStayLevel = RoomStay.PREFIX + KeyValueHelper.SEPARATOR + propertyID + KeyValueHelper.SEPARATOR + roomTypeId;
        for (RoomStay roomStay : roomStayCacheService.loadAll(roomStayLevel)) {
            Date start = DateTimeUtils.parse(roomStay.getStart());
            Date end = DateTimeUtils.parse(roomStay.getEnd());
            if (checkInDate.compareTo(start) >= 0
                    && DateTimeUtils.addHours(checkOutDate, DELAY_ONE_DAY).compareTo(end) <= 0
                    && !losIsAvailable(los, roomStay)) {
                return true;
            }
        }
        return false;
    }

    private boolean losIsAvailable(int los, RoomStay roomStay) {
        return (los >= roomStay.getMinStay() && roomStay.getMaxStay() == 0) ||
                (los >= roomStay.getMinStay() && los <= roomStay.getMaxStay());
    }

    public void setRoomStayCacheService(RoomStayCacheService roomStayCacheService) {
        this.roomStayCacheService = roomStayCacheService;
    }

    public void setParseRoomStayService(ParseRoomStayService parseRoomStayService) {
        this.parseRoomStayService = parseRoomStayService;
    }
}
